using System;
using System.Collections.Generic;
using System.Linq;
using ExtendedMvc.Common.Diagnostics;
using ExtendedMvc.Html;

namespace ExtendedMvc.Elements {
	public class TextArea<TModel> : TextAreaBase<TextArea<TModel>, TModel> where TModel : class {
		public TextArea(IModelViewHelper<TModel> helper, string memberName, string text = null, string id = null) : base(helper, memberName, text, id) { }

		public TextArea(IModelViewHelper<TModel> helper, string memberName, IEnumerable<string> lines = null, string id = null) : base(helper, memberName, lines, id) { }
	}

	public abstract class TextAreaBase<T, TModel> : FormElement<T, TModel>
		where T : TextAreaBase<T, TModel>
		where TModel : class {
		private int? _maxLength;
		private int? _rows;
		private int? _columns;

		protected IEnumerable<string> lines { get; private set; }
		protected bool required { get; private set; }

		protected TextAreaBase(IModelViewHelper<TModel> helper, string memberName, IEnumerable<string> lines, string id = null)
			: base(helper, HtmlTag.TextArea, id ?? memberName, memberName) {
			Text(lines);
			if (metadata != null) required = metadata.IsRequired;
		}

		protected TextAreaBase(IModelViewHelper<TModel> helper, string memberName, string text, string id = null) : this(helper, memberName, new List<string>() { text }, id) { }

		public virtual T Rows(int value) {
			Check.Argument.IsNotNegative(value, "value");
			_rows = value == 0 ? (int?)null : value;
			return (T)this;
		}

		public virtual T Columns(int value) {
			Check.Argument.IsNotNegative(value, "value");
			_columns = value == 0 ? (int?)null : value;
			return (T)this;
		}

		public virtual T Size(int columns, int rows) {
			Check.Argument.IsNotZeroOrNegative(columns, "columns");
			Check.Argument.IsNotZeroOrNegative(rows, "rows");
			_columns = columns;
			_rows = rows;
			return (T)this;
		}

		public virtual T MaxLength(int value) {
			Check.Argument.IsNotNegative(value, "value");
			_maxLength = value == 0 ? (int?)null : value;
			return (T)this;
		}

		public virtual T Text(object value) {
			lines = new List<string>() { value.ToString() };
			return (T)this;
		}

		public virtual T Text(IEnumerable<object> lines) {
			this.lines = lines.Cast<string>();
			return (T)this;
		}

		public virtual T Text(params object[] lines) {
			Text(lines.AsEnumerable());
			return (T)this;
		}

		protected override void Prepare() {
			if (_maxLength != null) SetAttribute(HtmlAttribute.MaxLength, _maxLength.Value);
			if (_rows != null) SetAttribute(HtmlAttribute.Rows, _rows.Value);
			if (_columns != null) SetAttribute(HtmlAttribute.Cols, _columns.Value);
			base.Prepare();
		}

		protected override void SetContent() {
			Builder.InnerHtml = lines.Aggregate(string.Empty, (a, b) => a + (string.IsNullOrEmpty(a) ? string.Empty : Environment.NewLine) + b);
		}
	}
}
